package com.xiashitech.apiservice.allmem;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xiashitech.apiservice.Constants.DBType;
import com.xiashitech.apiservice.Constants.ErrorCode;
import com.xiashitech.apiservice.Constants.Operate;
import com.xiashitech.apiservice.config.AgentConfig;
import com.xiashitech.apiservice.config.AuthConfig;
import com.xiashitech.apiservice.dao.PassappMapper;
import com.xiashitech.apiservice.dao.model.Passapp;
import com.xiashitech.apiservice.dto.*;
import com.xiashitech.interfaces.agent.dto.AgentConfigDTO;
import com.xiashitech.interfaces.apiservice.dto.base.Column;
import com.xiashitech.interfaces.apiservice.dto.base.Table;
import com.xiashitech.interfaces.authservice.AuthService;
import com.xiashitech.interfaces.authservice.dto.AuthDTO;
import com.xiashitech.sqlparser.sqlvisitor.Constants.ParserConstant;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.lang.System;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor =@_(@Autowired))
public class DbMemManager {
    private static final Log log = LogFactory.get();

    final static ThreadPoolExecutor authTableExecutor = new ThreadPoolExecutor(200, 300,
            30, TimeUnit.SECONDS,
            new LinkedBlockingDeque<Runnable>(50000000));
    private AtomicReference<WholeDbMemory> ref = new AtomicReference<>();
    private final ScheduledExecutorService executorServiceForConfig = Executors.newScheduledThreadPool(1);
    private final AgentConfig agentConfig;
    private final AuthConfig authConfig;
    private final AuthService authService;
    private final PassappMapper passappMapper;
    private volatile int updatecache = 1; // 0，表示不需要更新缓存，1，表示需要更新缓存，默认为 1，启动时即创建
    private volatile int cacheupdating = 0; // 0，表示没在更新缓存，1，表示正在更新缓存
    private volatile long cacheStartMillis = System.currentTimeMillis(); // 表示缓存开始生成时间
    private volatile long cacheCompleteMillis = System.currentTimeMillis(); // 表示缓存生成结束时间

    private Map<String, List<MetaDataTable>> mapSystemTableList; // 仅仅用于 vmtool 内存查看，
    private Map<String, List<String>> mapSystemUserList; // 仅仅用于 vmtool 内存查看，

    private final String[] sqlTypeConstants = new String[]{ParserConstant.SELECT,ParserConstant.DELETE,ParserConstant.UPDATE,ParserConstant.INSERT};
    public WholeDbMemory getDbInfoInMemory() {
        if(ref.get() == null) {
            WholeDbMemory wholeDbMemory = WholeDbMemory.builder()
                    .metaDataDBS(new ArrayList<>())
                    .metaDataDBServices(new ArrayList<>())
                    .tableIdMap(new ConcurrentHashMap<>())
                    .userAuthTableMap(new ConcurrentHashMap<>())
                    .build();
            ref.set(wholeDbMemory);
        }
        return ref.get();
    }
    @PostConstruct
    private void initMem() {
         executorServiceForConfig.scheduleWithFixedDelay(()->{
             if(!authConfig.isUseAllAuthInMemory())
                 return;
             if(updatecache == 0 && System.currentTimeMillis() - cacheCompleteMillis < 24 * 3600*1000)
                 return;
             cacheupdating = 1;
             cacheStartMillis = System.currentTimeMillis();
             try {
                 buildDbInfoInMemory();
             } catch (Throwable e) {
                 e.printStackTrace();
             }
             cacheCompleteMillis = System.currentTimeMillis();
             cacheupdating = 0;
             updatecache = 0;
         }, 10, 1, TimeUnit.SECONDS);
    }

    public int getUpdatecache() {
        return updatecache;
    }

    public void setUpdatecache(int updatecache) {
        this.updatecache = updatecache;
    }

    public int getCacheupdating() {
        return cacheupdating;
    }

    public long getCacheStartMillis() {
        return cacheStartMillis;
    }

    public long getCacheCompleteMillis() {
        return cacheCompleteMillis;
    }

    private synchronized void buildDbInfoInMemory() {
        log.info("buildDbInfoInMemory enter");
        WholeDbMemory.WholeDbMemoryBuilder dbInfoBuilder = WholeDbMemory.builder();
        // 从 nacos 的配置中获取所有 systemId 和 appCode
        Map<String, String> sysmap = agentConfig.getSystemAppCode();
        List<String> systemIds = sysmap.entrySet().stream().map(entry -> entry.getKey()).filter(item-> !"usegrpc".equalsIgnoreCase(item) && !"stopauth".equalsIgnoreCase(item) ).collect(Collectors.toList());
        log.info("buildDbInfoInMemory sysmap size: {}", sysmap.size());

        // 构建 MetaDataDBService List
        String dbService = HttpUtil.createGet(authConfig.getMetaDataUrlForDBService()).execute().body();
        List<MetaDataDBService> metaDataDBServices = JSONUtil.toList(JSONUtil.parseObj(dbService).get("data").toString(), MetaDataDBService.class);
        dbInfoBuilder.metaDataDBServices(metaDataDBServices);
        log.info("buildDbInfoInMemory dbService size: {}", metaDataDBServices.size());

        // 构建 MetaDataDB List
        String schemas = HttpUtil.createGet(authConfig.getMetaDataUrlForDB()).execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(schemas);
        List<MetaDataDB> metaDataDBS = JSONUtil.toList(jsonObject.get("data").toString(), MetaDataDB.class);
        dbInfoBuilder.metaDataDBS(metaDataDBS);
        log.info("buildDbInfoInMemory metaDataDBS size: {}", metaDataDBS.size());

        // http://192.168.2.2/api/v1/tables?database=jsh-erp.default.jsh_erp
        // http://192.168.2.2/api/v1/tables?database={}&limit=1000
        // 不修改配置对象，从关联配置中获取信息，避免升级引起忘了配置出现异常
        String tmpUrl = authConfig.getMetaDataUrlForDB();
        // TODO 这里应该做分页，目前只取前 1000 条，对于大库，还是有风险
        String allTablesUrl = tmpUrl.substring(0, tmpUrl.indexOf("/api")) + "/api/v1/tables?database={}&limit=500{}";
        // 查找各个 systemId 对应哪些 service，以及这些 service 有哪些 database，最后建立 systemId 下有哪些 table
        List<Map<String, List<MetaDataTable>>>  tmpTableList = systemIds.stream().map(systemId -> {
            // systemId 中的 service
            List<String> dbservices = new ArrayList();
            List<MetaDataDBService>  metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().equals(systemId)).collect(Collectors.toList());
            if(metaDataDBServicesAfterFilter.size() > 0) {
                dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
            } else {
                metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getDescription() != null && metaDataDBService.getDescription().contains("#"+systemId+"#")).collect(Collectors.toList());
                if(metaDataDBServicesAfterFilter.size() > 0) {
                    dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                } else {
                    metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().contains(systemId)).collect(Collectors.toList());
                    if(metaDataDBServicesAfterFilter.size() > 0) {
                        dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                    }
                }
            }
            log.info("buildDbInfoInMemory systemId -->> Service: {} --> {} ", systemId, JSONUtil.toJsonStr(dbservices));

            List<MetaDataDB> systemDataDBs = metaDataDBS.stream().filter(metaDataDB -> {
                if(dbservices.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName+".")).count() > 0) {
                    return true;
                }
                return false;
            }).collect(Collectors.toList());
            log.info("buildDbInfoInMemory systemId -->> Service -->> dbs: {} --> {} --> {}/{} ", systemId, JSONUtil.toJsonStr(dbservices),systemDataDBs.size(), JSONUtil.toJsonStr(systemDataDBs) );

            Map<String, List<MetaDataTable>> metaDataDbTables = new HashMap<>();
            try {
                metaDataDbTables = systemDataDBs.stream().map(dataDB -> {
                    String fullyQualifiedName = dataDB.getFullyQualifiedName();
                    String[] qualifiedArr = fullyQualifiedName.split("\\.");
                    // 生成 key，而不是直接使用 systemId 作为 key，为避免同一个 systemId 多个 db 下的表重名
                    String tableMapKey = systemId + "." + qualifiedArr[0] + "." + dataDB.getName();  // 取时使用 servisename + 参数中 schema（finalAuthFactDTO.getSchema()）
                    String afterStr = "";//""&after=";
                    int pageCnt = 1;
                    boolean isPage = true;
                    List<MetaDataTable> metaDataTables = new ArrayList<>();
                    while(isPage) {
                        String metaDataUrlForTable = StrUtil.format(allTablesUrl, fullyQualifiedName, afterStr);
                        // log.info("buildDbInfoInMemory systemId -->> metaDataUrlForTable: {} --> {} ", systemId, metaDataUrlForTable);
                        List<MetaDataTable> metaDataTablesPage = new ArrayList<>();
                        try {
                            // if (!"mysql".equalsIgnoreCase(dataDB.getServiceType())) {
                            //     tableMapKey = systemId + "." + qualifiedArr[0] + "." + dataDB.getName();// qualifiedArr[2];  // TODO 取时使用 servicename + 参数中的 database（finalAuthFactDTO.getDatabase()）, 应该对应数组索引 2
                            // } // TODO 针对 Oracle 等其他的可能需要添加额外的逻辑
                            String tablests = HttpUtil.createGet(metaDataUrlForTable).execute().body();
                            JSONObject resp = JSONUtil.parseObj(tablests);
                            // 检查是否需分页
                            int count = resp.getJSONObject("paging").getInt("total");
                            if (count > 900 && "".equalsIgnoreCase(afterStr)) // 只打印一次
                                log.info("buildDbInfoInMemory table outlimit, systemId: {}, dbQualifyName: {}, total tables count: {} ", systemId, fullyQualifiedName, count);
                            String dataStr = resp.get("data").toString();
                            metaDataTablesPage = JSONUtil.toList(dataStr, MetaDataTable.class);
                            metaDataTables.addAll(metaDataTablesPage);
                            log.info("buildDbInfoInMemory systemId -->> db -->> metaDataUrlForTable -->> tableMapKey -->> pageCnt -->> tables-size: {} --> {} --> {} --> {} --> {} --> {}", systemId, dataDB.getName(), metaDataUrlForTable, tableMapKey, pageCnt, metaDataTablesPage.size());
                            String afterNo = resp.getJSONObject("paging").getStr("after");
                            if(afterNo != null) { // 还有下一页
                                pageCnt++;
                                afterStr = "&after=" + afterNo;
                                // log.info("buildDbInfoInMemory systemId -->> db -->> metaDataUrlForTable -->> tableMapKey -->> hasAfter -->> tables-size: {} --> {} --> {} --> {} --> {} --> {} ", systemId, JSONUtil.toJsonStr(dataDB), metaDataUrlForTable, tableMapKey, afterStr, metaDataTables.size());
                            } else {
                                isPage = false;
                            }
                        } catch (Exception e) {
                            log.info(" buildDbInfoInMemory Exception: systemId -->> db -->> metaDataUrlForTable -->> tables-size: {} --> {} --> {} --> {} --E: {}", systemId, JSONUtil.toJsonStr(dataDB), metaDataUrlForTable, metaDataTablesPage.size(), e.getMessage());
                            e.printStackTrace();
                        }
                    }
                    log.info(" buildDbInfoInMemory systemId -->> pageCnt -->> tables total size: {} --> {} --> {}", systemId, pageCnt, metaDataTables.size());
                    return new AbstractMap.SimpleEntry<>(tableMapKey, metaDataTables);
                    //log.info("buildDbInfoInMemory in {}, tables size: {}", fullyQualifiedName, metaDataDBS.size());
                }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

                // fullyQualifiedName.TABLENAME 这两个应该一样：metaDataTable.getFullyQualifiedName(),
                //List<MetaDataTable> dataTables =  metaDataDbTables.stream().flatMap(Collection::stream).collect(Collectors.toList());
                log.info("systemId -->> Service -->> dbs -->> tables-size: {} --> {} --> {} --> {} ", systemId, JSONUtil.toJsonStr(dbservices), JSONUtil.toJsonStr(systemDataDBs), metaDataDbTables.size());
                return metaDataDbTables;
            } catch (Throwable t) {
                log.info("buildDbInfoInMemory Exception build metaDataDbTables exception: " + t.getMessage());
                t.printStackTrace();
            }
            return metaDataDbTables;
        }).collect(Collectors.toList());

        Map<String, List<MetaDataTable>> systemTableMap = new HashMap<>();
        for(Map<String, List<MetaDataTable>> tmpMap: tmpTableList) {
            for(Map.Entry<String, List<MetaDataTable>> entry: tmpMap.entrySet()) {
                if(systemTableMap.get(entry.getKey()) != null) {
                    log.warn("buildDbInfoInMemory 存在相同的Key，可能存在错误，skip");
                    continue;
                }
                systemTableMap.put(entry.getKey(), entry.getValue());
            }
        }
        log.info("buildDbInfoInMemory systemTableMap size: {}", systemTableMap.size());
        systemTableMap.entrySet().stream().forEach(entry-> log.info("buildDbInfoInMemory systemTableMap key: {}, tablecount: {}", entry.getKey(), entry.getValue().size()));
        mapSystemTableList = systemTableMap;

        // 构建用户系统下的用户信息
        if(authConfig.getUserCategoryUrl() == null || authConfig.getUserListByCategoryUrl() == null) {
            log.error("buildDbInfoInMemory. You NEED config userCategoryUrl and userListByCategoryUrl.");
            return;
        }
        // 获取用户分类
        String userCategoryUrl =  StrUtil.format(authConfig.getUserCategoryUrl(), "id", 1000);
        log.info("buildDbInfoInMemory userCategoryUrl: {}", userCategoryUrl);
        String allCategoryString = HttpUtil.createGet(userCategoryUrl).execute().body();
        JSONObject resp = JSONUtil.parseObj(allCategoryString);
        JSONObject dataObj = resp.getJSONObject("data");
        int cateCnt = dataObj.getInt("count"); // category 总数
        if(cateCnt > 900)  log.info("buildDbInfoInMemory category outlimit, total count: {} ", cateCnt);
        String listStr = dataObj.get("results").toString(); // ((JSONObject)JSONUtil.parseObj(allCategoryString).get("data")).get("results").toString()
        List<UserCategory> userCategoryList = JSONUtil.toList(listStr, UserCategory.class);
        Map<String, List<String>> systemUserMap = userCategoryList.stream().filter(userCategory -> {
            if(systemIds.stream().anyMatch(systemId -> systemId.equalsIgnoreCase(userCategory.getDomain())))
                return true;
            return false;
        }).map(userCategory -> {
            final int pageSize = 100;
            String userListUrl = StrUtil.format(authConfig.getUserListByCategoryUrl(), userCategory.getId(), pageSize,"");
            String userstr = HttpUtil.createGet(userListUrl).execute().body();
            JSONObject respUser = JSONUtil.parseObj(userstr);
            Integer userCnt = respUser.getInt("count");
            if(userCnt == null) { // 出错了，没有 count 字段
                log.info("buildDbInfoInMemory user category({},{}) response error", userCategory.getId(), userCategory.getDisplay_name());
                return new AbstractMap.SimpleEntry<>(userCategory.getDomain(), new ArrayList<String>());
            }
            //if(userCnt > 9000) log.info("buildDbInfoInMemory category (id:{}, name:{}) user outlimit, total user count: {}", userCategory.getId(), userCategory.getDisplay_name(), userCnt);
            //log.info("buildDbInfoInMemory category (id:{}, name:{}) total user count: {}", userCategory.getId(), userCategory.getDisplay_name(), userCnt);
            List<UserProfile> userProfileList = JSONUtil.toList(respUser.get("results").toString(), UserProfile.class);
            List<String> userIds = userProfileList.stream().map(up-> up.getUsername()).collect(Collectors.toList());

            int pageCnt = userCnt/pageSize;
            int leftCnt = userCnt%pageSize;
            if(leftCnt > 0) pageCnt++;
            log.info("buildDbInfoInMemory user category({},{}) , total page count {}, now page index 1, user count: {}, url: {}", userCategory.getId(), userCategory.getDisplay_name(), pageCnt, userIds.size(), userListUrl);
            for(int pageIdx = 2; pageIdx <= pageCnt; pageIdx++) {
                userListUrl = StrUtil.format(authConfig.getUserListByCategoryUrl(), userCategory.getId(), pageSize, "&page=" + pageIdx);
                userstr = HttpUtil.createGet(userListUrl).execute().body();
                respUser = JSONUtil.parseObj(userstr);
                userProfileList = JSONUtil.toList(respUser.get("results").toString(), UserProfile.class);
                List<String> userIdsTmp = userProfileList.stream().map(up-> up.getUsername()).collect(Collectors.toList());
                log.info("buildDbInfoInMemory user category({},{}) , total page count {}, now page index {}, user count: {}, pageSize: {}", userCategory.getId(), userCategory.getDisplay_name(), pageCnt, pageIdx, userIdsTmp.size(), pageSize);
                userIds.addAll(userIdsTmp);
            }
            if(pageCnt > 1) log.info("buildDbInfoInMemory user category({},{}) , total page count {}, total user count: {}", userCategory.getId(), userCategory.getDisplay_name(), pageCnt, userIds.size() );
            return new AbstractMap.SimpleEntry<>(userCategory.getDomain(), userIds);
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        log.info("buildDbInfoInMemory systemUserMap size: {}, ", systemUserMap.size());
        systemUserMap.entrySet().stream().forEach(entry-> log.info("buildDbInfoInMemory systemUserMap key: {}, usercount: {}", entry.getKey(), entry.getValue().size()));
        mapSystemUserList = systemUserMap;

        // select pa.auth_token as auth_token from paas_app pa where pa.code = #{code,jdbcType=VARCHAR}
        List<Passapp> passappList = passappMapper.selectCodeTokenList();
        Map<String, Passapp> appPassMap = passappList.stream().collect(Collectors.toMap(Passapp::getCode, Function.identity()));
        log.info("buildDbInfoInMemory appPassMap size: {}, {}", appPassMap.size(), JSONUtil.toJsonStr(appPassMap));

        // 模拟 systemId 和 userIds
        //for(String systemId: systemIds) {
        ConcurrentHashMap<String, String> tableIdMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<String, Table> mapTable = new ConcurrentHashMap<>();
        int systemIdx = 0;
        for(Map.Entry<String, List<MetaDataTable>> systemMapEntry: systemTableMap.entrySet()) {
            systemIdx++;
            String key1 = systemMapEntry.getKey();
            String[] keyArr = key1.split("\\.");
            String systemId = keyArr[0];
            List<MetaDataTable> tables = systemMapEntry.getValue();
            if(tables == null) {
                log.info("buildDbInfoInMemory systemTableMap now start: key {} tables is null", key1);
                continue;
            }
            List<String> userids = systemUserMap.get(systemId);
            if(userids == null) {
                log.info("buildDbInfoInMemory systemTableMap now start: systemId {}, key {} userids is null", systemId, key1);
                continue;
            }
            log.info("buildDbInfoInMemory systemTableMap now startA. key1: {}, table count: {}, user count: {}", key1, tables.size(), userids.size());
            String appCode = sysmap.get(systemId);
            Passapp passapp = appPassMap.get(appCode);
            if(passapp == null || passapp.getAuth_token() == null || "".equals(passapp.getAuth_token())) {
                log.info("buildDbInfoInMemory passapp fail, systemId: {}, appCode: {} has not auth_token", systemId, appCode);
                continue;
            }
            String secret = passapp.getAuth_token();

            int userIdx = 0;
            // log.info("buildDbInfoInMemory , {}, userids size: {}, tables size: {}, appCode: {}, secret: {}", systemId, userids.size(), tables.size(), appCode, secret);
            for(String userid: userids) {
            // userids.parallelStream().forEach( userid -> {
                // log.info("buildDbInfoInMemory systemTableMap now startB. key1: {}, user: {}, now table: {}, now user: {}", key1, userid, tables.size(), userids.size());
                userIdx++;
                int tableIdx = 0;
                for(MetaDataTable table: tables) {
                // tables.parallelStream().forEach( table->{
                    tableIdx++;
                    if(userIdx % 20 == 0 && tableIdx % 10 == 0) // 减少日志打印量
                        log.info("buildDbInfoInMemory systemTableMap now startC. key1: {}, user: {}, table: {}, now system: {}/{}, now table: {}/{}, now user: {}/{}, activeCnt: {}", key1, userid, table.getName(), systemIdx, systemTableMap.size(), tableIdx, tables.size(), userIdx, userids.size(), authTableExecutor.getActiveCount());
                    try {
                        /**
                         * 获取表、列的权限
                         */
                        String tableFullyQualifiedName = table.getFullyQualifiedName();
                        String[] qualifiedArr = tableFullyQualifiedName.split("\\.");
                        Table authTable = Table.builder()
                            .tabName(table.getName())
                            .columns(table.getColumns().stream().map(metaColumn-> Column.builder().colName(metaColumn.getName()).build()).collect(Collectors.toList()))
                            .build();
                        if(!tableIdMap.contains(tableFullyQualifiedName))
                            tableIdMap.put(tableFullyQualifiedName, table.getId());
                        String iamUserId = userid + "@" + systemId;
                        Arrays.stream(sqlTypeConstants).parallel().forEach( st -> {
                            String action = st;
                            String instance = keyArr[1]; // 应该一样 qualifiedArr[0]
                            String dbname = qualifiedArr[1];
                            String schema = qualifiedArr[2];
                            String localSqlType = action; // resultDTO.getSqlType();
                            // log.info("buildDbInfoInMemory iamUserId: {}, action: {}, instance: {}, dbname: {}, schema: {}, appCode: {}, secret: {}", iamUserId, action, instance, dbname, schema, appCode, secret);

                            // systemId + fullQualiyFile[0] + fullQualiyFile[1] + userId + tableName + sqlType
                            String tableKey = key1 + "." + userid + "." + table.getName() + "." + st;
                            AuthDTO authDTO = AuthDTO.builder().systemId(systemId).userId(iamUserId).actionId(action)
                                    .databaseService(instance).databaseName(dbname).databaseSchema(schema)
                                    .appCode(appCode).appSecret(secret).iamBaseUrl(authConfig.getIamBaseUrl()).build();
                            authDTO.setTableName(authTable.getTabName());
                            //获取表权限
                            // AuthDTO tabAuthResult = authService.verifyAuth(authDTO);
                            authTableExecutor.submit(()->{
                                try {
                                    AuthDTO tabAuthResult = authService.verifyAuth(authDTO);
                                    authTable.setTabAuth(tabAuthResult.isAuth());
                                    authTable.setTabAuthReason(tabAuthResult.getResult());
                                } catch (Throwable t) {
                                    log.info("buildDbInfoInMemory 提交 {} 表校验时异常：{}",authDTO.getTableName(), t.getMessage());
                                    t.printStackTrace();
                                }
                            });
                            // log.info("buildDbInfoInMemory tabAuthResult: {}", JSONUtil.toJsonStr(tabAuthResult));

                            //获取列权限，只有当 SELECT 和 UPDATE 时需要
                            if (authTable.getColumns() != null && !Operate.INSERT.name().equals(localSqlType) && !Operate.DELETE.name().equals(localSqlType)) {
                                authTable.getColumns().parallelStream().forEach(column -> {
                                    AuthDTO authColDTO = BeanUtil.copyProperties(authDTO, AuthDTO.class);
                                    authColDTO.setColumnName(column.getColName());
                                    authTableExecutor.submit(()->{
                                        try {
                                            AuthDTO colAuthResult = authService.verifyAuth(authColDTO);
                                            // log.info("buildDbInfoInMemory colAuthResult: operator: {}, result: {}", localSqlType, JSONUtil.toJsonStr(tabAuthResult));
                                            column.setColAuth(colAuthResult.isAuth());
                                            column.setColAuthReason(colAuthResult.getResult());
                                        } catch (Throwable t) {
                                            log.info("buildDbInfoInMemory 提交 {} 表的字段 {} 校验时异常：{}",authColDTO.getTableName(), authColDTO.getColumnName(), t.getMessage());
                                            t.printStackTrace();
                                        }
                                    });
                                });
                            }
                            // 这里应该有问题，可能鉴权线程还没执行，这个线程就把表名和字段清空了
                            // authDTO.setTableName(null);
                            // authDTO.setColumnName(null);
                            mapTable.put(tableKey, authTable);
                            // log.info("buildDbInfoInMemory authTable: key: {}, authTable: {}", tableKey, JSONUtil.toJsonStr(authTable));
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                };
            };
        }
        int waitCnt = 0;
        while(authTableExecutor.getQueue().size()>0){
            try {
                if(waitCnt % 60 == 0) {
                    log.info("buildDbInfoInMemory continue waiting ....... elasped: {}, size: {}", waitCnt, authTableExecutor.getQueue().size());
                    log.info("now taskCount: {}, completedTaskCount: {}, largestPoolSize: {}, poolSize: {}, activeCount: {}",authTableExecutor.getTaskCount(),authTableExecutor.getCompletedTaskCount(),authTableExecutor.getLargestPoolSize(),authTableExecutor.getPoolSize(),authTableExecutor.getActiveCount());
                }
                TimeUnit.SECONDS.sleep(1);
                waitCnt++;
            } catch (Exception e) {

            }
        }
        log.info("buildDbInfoInMemory finished ....... total elasped: {}, tableIdMap size: {}, authTable size: {}", waitCnt, tableIdMap.size(), mapTable.size());
        dbInfoBuilder.tableIdMap(tableIdMap);
        dbInfoBuilder.userAuthTableMap(mapTable);
        ref.set(dbInfoBuilder.build());
    }
}
